package com.atguigu.distributed.lock.redis.redisson.service;

import com.atguigu.distributed.lock.lock.DistributeLookClientFactory;
import com.atguigu.distributed.lock.pojo.Stock;
import com.atguigu.distributed.lock.redis.lock.DistributedRedisLock;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author linjy on 2022/10/10
 */
@Service
public class RedissonService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    @Autowired
    private RedissonClient redissonClient;


    /**
     * 闭锁
     */
    public void testLatch() {
        RCountDownLatch latch = this.redissonClient.getCountDownLatch("latch");
        latch.trySetCount(6);

        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void testCountDown() {
        RCountDownLatch latch = this.redissonClient.getCountDownLatch("latch");
        latch.trySetCount(6);

        latch.countDown();
    }


    /**
     * 信号量锁
     */
    public void testSemaphore() {
        RSemaphore semaphore = this.redissonClient.getSemaphore("semaphore");
        //设置资源量限流的线程数
        semaphore.trySetPermits(5);
        try {
            semaphore.acquire(); //获取资源，获取资源成功的线程可以继续处理业务操作。否则会被阻塞住
            this.stringRedisTemplate.opsForList().rightPush("log", "10086获取了资源，开始处理业务逻辑。" + Thread.currentThread().getName());
            TimeUnit.SECONDS.sleep(10 + new Random().nextInt(10));
            this.stringRedisTemplate.opsForList().rightPush("log", "10086处理完业务逻辑，释放资源========" + Thread.currentThread().getName());
            semaphore.release();//手动释放资源
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    /**
     * 读写锁
     */
    public String testRead() {
        RReadWriteLock rwLock = this.redissonClient.getReadWriteLock("rwLock");
        rwLock.readLock().lock(10, TimeUnit.SECONDS);

        System.out.println("测试读锁。。。。");
        // rwLock.readLock().unlock();

        return null;
    }

    public String testWrite() {
        RReadWriteLock rwLock = this.redissonClient.getReadWriteLock("rwLock");
        rwLock.writeLock().lock(10, TimeUnit.SECONDS);

        System.out.println("测试写锁。。。。");
        // rwLock.writeLock().unlock();

        return null;
    }

    /**
     * 公平锁
     */
    public void deduct2() {
        // 加锁，获取锁失败重试
        RLock fairLock = this.redissonClient.getFairLock("anyLock");
        fairLock.lock();//默认情况下，看门狗的检查锁的超时时间是30秒钟,只要应用程序不结束,过一会儿（10秒）就会重新设置过期时间为30秒
        //fairLock.lock(10, TimeUnit.SECONDS);//加锁10秒，10后即使不手动释放锁，也会自动释放锁
        //fairLock.tryLock(100,10,TimeUnit.SECONDS);//尝试加锁，最多等待100秒，上锁以后10秒内自动解锁

        try {
            // 1. 查询库存信息
            String stock = stringRedisTemplate.opsForValue().get("stock").toString();

            // 2. 判断库存是否充足
            if (stock != null && stock.length() != 0) {
                Integer st = Integer.valueOf(stock);
                if (st > 0) {
                    // 3.扣减库存
                    stringRedisTemplate.opsForValue().set("stock", String.valueOf(--st));
                }
            }
        } finally {
            // 释放锁
            fairLock.unlock();
        }
    }


    /**
     * 可重入锁
     */
    public void deduct() {
        // 加锁，获取锁失败重试
        RLock lock = this.redissonClient.getLock("lock");
        lock.lock();//默认情况下，看门狗的检查锁的超时时间是30秒钟,只要应用程序不结束,过一会儿（10秒）就会重新设置过期时间为30秒
        //lock.lock(10, TimeUnit.SECONDS);//加锁10秒，10后即使不手动释放锁，也会自动释放锁
        //lock.tryLock(100,10,TimeUnit.SECONDS);//尝试加锁，最多等待100秒，上锁以后10秒内自动解锁

        try {
            // 1. 查询库存信息
            String stock = stringRedisTemplate.opsForValue().get("stock").toString();

            // 2. 判断库存是否充足
            if (stock != null && stock.length() != 0) {
                Integer st = Integer.valueOf(stock);
                if (st > 0) {
                    // 3.扣减库存
                    stringRedisTemplate.opsForValue().set("stock", String.valueOf(--st));
                }
            }
            test();
        } finally {
            // 释放锁
            lock.unlock();
        }

    }

    /**
     * 测试可重入锁
     */
    public void test() {
        RLock lock = this.redissonClient.getLock("lock");
        lock.lock();
        System.out.println("测试可重入锁");
        lock.unlock();
    }


}
